package project3;

import java.net.*;
import java.io.*;
import java.util.concurrent.BlockingQueue;

public class ReaderThread extends Thread {
	private boolean dead;
	private BlockingQueue<Cell> buffer;
	private IntermediateRouter inter;
	private DataInputStream in;
	
	public ReaderThread(BlockingQueue<Cell> buffer, Socket sock, IntermediateRouter inter) {
		this.dead = false;
		this.buffer = buffer;
		this.inter = inter;
		
		try {			
			in = new DataInputStream(sock.getInputStream());
		} catch (Exception e) {
			System.err.println("DataInputStream constructor threw an exception");
			e.printStackTrace();
		}
	}
	
	public void run() {
		byte[] buffer = new byte[Util.CELL_LENGTH];
		
		while(true) {
			try {
				in.readFully(buffer);				
				Cell curCell = Cell.createCell(buffer);
				int curCellCircId = curCell.getCircId();
				
				if (curCell.getCellType() == Util.CellType.RELAY) {
					// if (cell cmd is Relay Connected / RelayBeginFailed / RelayExtended/ RelayExtendFailed && there is a Relay worker thread waiting)
					RelayCell curRelayCell = (RelayCell) curCell;
					if (curRelayCell.getRelayCmdType() == 0x04 ||
							curRelayCell.getRelayCmdType() == 0x07 ||
							curRelayCell.getRelayCmdType() == 0x0b ||
							curRelayCell.getRelayCmdType() == 0x0c)
						// tell SourceRouter
						SourceRouter.setResponse(curRelayCell);
					else if (inter.isEndRouter(curRelayCell.getCircId())) {
						if (curRelayCell.getRelayCmdType() == 0x01)
							// tell IntermediateRouter to create a stream / close a stream / spawn a Create worker thread
							inter.associateStreamWithWebserver(curRelayCell);
						else if (curRelayCell.getRelayCmdType() == 0x03) {
							inter.endStreamWithWebserver(curRelayCell);
						} else if (curRelayCell.getRelayCmdType() == 0x06) {
							inter.createHop(curRelayCell);
						} else if (curRelayCell.getRelayCmdType() == 0x02) 
//							// send data to proxy's buffer
							ProxyServerWrapper.handleRequest(curRelayCell.getStreamId(), curRelayCell.getBody());
								
					} else {// I am neither a src router nor an end router
						if (((RelayCell) curCell).getRelayCmdType() == 0x02) {
							// Relay Data: 
							// modify the cell's circuit id, put to the correct buffer
							inter.setMappedCircuitId(curCellCircId, curCell);
							inter.putToMappedCircuitBuffer(curCell);
					}
				} else { // cell is ConnectionCell
					if (curCell.getCellType() == Util.CellType.OPEN) 
						respondToOpen(curCell);					
					else if (curCell.getCellType() == Util.CellType.CREATE)
						 // tell IntermediateRouter to populate the routing table (maybe check whether the circuit id is okay or not
						 // if enforcing incoming circuit number uniqueness) and send back Created if successful
						respondToCreate(curCell);
					else if (cell.getCellType() == Util.CellType.DESTROY)
						// tell IntermediateRouter to erase the entry in the routing table (no response)
						destroyCircuit(curCell.getCircId());					 
					else if (cell.getCellType() == Util.CellType.OPENED ||
							 cell.getCellType() == Util.CellType.OPEN_FAILED ||
							 cell.getCellType() == Util.CellType.CREATED ||
							 cell.getCellType() == Util.CellType.CREATE_FAILED)
						setResponse(curCell);						 
				}
			} catch (IOException e) {		
				e.printStackTrace();
			} 
		}
	}
}
